﻿using System;
using System.Linq;
using cludg.Domain.Environment;
using cludg.Repository.Environment;
using cludg.Repository.Security;
using cludg.Repository.Transactions;
using cludg.Infrastructure.Core.Attributes;

namespace cludg.Services.Environment
{
	public class SettingService : ISettingService
	{
		[Dependency]
		public ITransactionFactory TransactionFactory { get; set; }

		[Dependency]
		public ISettingRepository Repository { get; set; }

		[Dependency]
		public ISecurityRepository SecurityRepository { get; set; }

		public IQueryable<Setting> All
		{
			get { return Repository.Get(); }
		}

		public void SetGlobal(string name, object value, string description = "")
		{
			SetSetting(SettingScope.Global, name, value, null, description);
		}

		public void SetUser(string name, object value, string userId, string description = "")
		{
			SetSetting(SettingScope.User, name, value, userId, description);
		}

		private void SetSetting(SettingScope scope, string name, object value, string userId, string description = "")
		{
			var settingFromRepo = Repository.ByScopeAndName(scope, name, userId);
			if (settingFromRepo != null)
			{
				settingFromRepo.ChangeDateTime = DateTime.Now;
				settingFromRepo.Value = value;
				if (!string.IsNullOrWhiteSpace(description))
					settingFromRepo.Description = description;
				using (var tran = TransactionFactory.BeginTransaction())
				{
					Repository.Save(settingFromRepo);
					tran.Commit();
				}
			}
			else
			{
				using (var tran = TransactionFactory.BeginTransaction())
				{

					Repository.Add(new Setting
					{
						ChangeDateTime = DateTime.Now,
						Name = name,
						Scope = scope,
						Value = value,
						Description = description,
						User = string.IsNullOrWhiteSpace(userId) ? null : SecurityRepository.GetUserById(userId)
					});
					tran.Commit();
				}
			}
		}

		public object GetGlobal(string name)
		{
			var setting = Repository.ByScopeAndName(SettingScope.Global, name, null);
			return setting != null ? setting.Value : null;
		}

		public object GetUser(string name, string userId)
		{
			var setting = Repository.ByScopeAndName(SettingScope.User, name, userId);
			return setting != null ? setting.Value : null;
		}

		public void DeleteGlobal(string name)
		{
			var setting = Repository.ByScopeAndName(SettingScope.Global, name, null);
			if (setting == null)
			{
				throw new ApplicationException(string.Format("Глобальная настройка приложения '{0}' не найдена.",
					name));
			}

			using (var tran = TransactionFactory.BeginTransaction())
			{
				Repository.Delete(SettingScope.Global, name, null);
				tran.Commit();
			}
		}

		public void DeleteUser(string name, string userId)
		{
			var setting = Repository.ByScopeAndName(SettingScope.User, name, userId);
			if (setting == null)
			{
				throw new ApplicationException(string.Format("Настройка приложения '{0}' для пользователя '{1}' не найдена.",
					name, userId));
			}

			using (var tran = TransactionFactory.BeginTransaction())
			{
				Repository.Delete(SettingScope.User, name, userId);
				tran.Commit();
			}
		}

		public object this[string name]
		{
			get { return GetGlobal(name); }
			set { SetGlobal(name, value); }
		}

		public object this[string name, string userId]
		{
			get { return GetUser(name, userId); }
			set { SetUser(name, value, userId); }
		}

	}
}
